package com.heima.commnet.service.Impl;

import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.commnet.service.CommentHotService;
import com.heima.commnet.service.CommentService;
import com.heima.common.constants.article.HotArticleConstants;
import com.heima.common.constants.message.UpdateArticleMess;
import com.heima.common.exception.CustException;
import com.heima.feign.UserFeign;
import com.heima.model.comment.dto.CommentDTO;
import com.heima.model.comment.dto.CommentLikeDTO;
import com.heima.model.comment.dto.CommentSaveDTO;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vo.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.Range;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

  @Autowired UserFeign userFeign;
  @Autowired MongoTemplate mongoTemplate;
  @Autowired CommentHotService commentHotService;
  @Autowired RabbitTemplate rabbitTemplate;

  /**
   * 保存评论
   *
   * @param dto
   * @return
   */
  @Override
  public ResponseResult saveComment(CommentSaveDTO dto) {

    ApUser user = AppThreadLocalUtils.getUser();
    if (user == null) {
      CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
    }
    // 远程调用，获取对应的user信息
    ResponseResult<ApUser> userResponseResult = userFeign.findUserById(user.getId());
    user = userResponseResult.getData();
    if (user == null || userResponseResult.getCode() != 0) {
      CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "登录状态有误");
    }
    // 保存评论
    ApComment apComment = new ApComment();
    apComment.setAuthorId(user.getId());
    apComment.setAuthorName(user.getName());
    apComment.setArticleId(dto.getArticleId());
    apComment.setType((short) 0);
    apComment.setChannelId(0);
    apComment.setContent(dto.getContent());
    apComment.setImage(user.getImage());
    apComment.setLikes(0);
    apComment.setReply(0);
    apComment.setFlag((short) 0);
    apComment.setOrd(0);
    apComment.setCreatedTime(new Date());
    apComment.setUpdatedTime(new Date());
    mongoTemplate.save(apComment);

    //发送消息
    UpdateArticleMess mess = new UpdateArticleMess();
    mess.setAdd(1);
    mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
    mess.setArticleId(dto.getArticleId());
    String s = JSON.toJSONString(mess);
    rabbitTemplate.convertAndSend(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_QUEUE,s);
    log.info("评论行为 发送消息的：{}",s);

    return ResponseResult.okResult();
  }

  /**
   * 保存评论点赞
   *
   * @param dto
   * @return
   */
  @Autowired RedissonClient redissonClient;

  @Override
  public ResponseResult like(CommentLikeDTO dto) {

    ApUser user = AppThreadLocalUtils.getUser();
    if (user == null) {
      CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
    }
    ApComment apComment;
    // 加锁
    RLock likeslock = redissonClient.getLock("likeslock");
    likeslock.lock();
    try {
      // 查询评论
      apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
      if (apComment == null) {
        CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
      }
      // 查询是否已经点赞
      Query query =
          Query.query(
              Criteria.where("authorId").is(user.getId()).and("commentId").is(dto.getCommentId()));
      @Range(min = 0, max = 1)
      Short operation = dto.getOperation();
      ApCommentLike commentLike = mongoTemplate.findOne(query, ApCommentLike.class);
      if (commentLike != null && operation.intValue() == 0) {
        CustException.cust(AppHttpCodeEnum.DATA_EXIST, "已经点赞过");
      }
      if (operation == 0) {
        // 进行点赞数量的加一
        apComment.setLikes(apComment.getLikes() + 1);
        mongoTemplate.save(apComment);
        // 保存评论的点赞
        ApCommentLike apCommentLike = new ApCommentLike();
        apCommentLike.setAuthorId(0);
        apCommentLike.setCommentId(dto.getCommentId());
        apCommentLike.setOperation((short) 0);
        mongoTemplate.save(apCommentLike);

        // 点赞数量大于10称为热点评论
        // 计算热点评论评论
        if (apComment.getLikes() >= 10 && apComment.getFlag().shortValue() == 0) {
          commentHotService.hotCommentExecutor(apComment); // 异步计算当前评论是否称为热点评论
        }

      } else {
        // 点赞数量减一
        if (apComment.getLikes() < 0) {
          apComment.setLikes(0);
        } else {
          apComment.setLikes(apComment.getLikes() - 1);
        }
        // 删除评论的点赞信息
        mongoTemplate.remove(query, ApCommentLike.class);
      }
    } finally {
      likeslock.unlock();
    }
    // 数据返回
    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put("likes", apComment.getLikes());
    return ResponseResult.okResult(resultMap);
  }

  /**
   * 查询评论列表信息
   *
   * @param dto
   * @return
   */
  @Override
  public ResponseResult findByArticleId(CommentDTO dto) {
    // 1 参数检查

    if (dto.getArticleId() == null) {
      CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
    }
    Integer size = dto.getSize();
    if (size == null || size <= 0) {
      dto.setSize(10);
    }

    // 2查询Mongo文章所有评论列表
    List<ApComment> apCommentList = null;
    // 是第一页，先查询热点评论
    if (dto.getIndex().intValue() == 1) {
      apCommentList =
          mongoTemplate.find(
              Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("flag").is(1))
                  .with(Sort.by(Sort.Direction.DESC, "likes")),
              ApComment.class);
      size = dto.getSize() - apCommentList.size();
      // 普通评论
      List<ApComment> nonapCommentList =
          mongoTemplate.find(
              Query.query(
                      Criteria.where("articleId")
                          .is(dto.getArticleId())
                          .and("createdTime")
                          .lt(dto.getMinDate())
                          .and("flag")
                          .is(0))
                  .limit(size)
                  .with(Sort.by(Sort.Direction.DESC, "createdTime")),
              ApComment.class);
      apCommentList.addAll(nonapCommentList);
    } else {
      // 不是第一页，直接查询
      Query query =
          Query.query(
                  Criteria.where("articleId")
                      .is(dto.getArticleId())
                      .and("createdTime")
                      .lt(dto.getMinDate())
                      .and("flaf")
                      .is(0))
              .limit(dto.getSize())
              .with(Sort.by(Sort.Direction.DESC, "createdTime"));
      apCommentList = mongoTemplate.find(query, ApComment.class);
    }
    //    Query query =  Query.query(Criteria.where("articleId").is(dto.getArticleId())
    //            .and("createdTime").lt(dto.getMinDate()))
    //            .limit(dto.getSize())
    //            .with(Sort.by(Sort.Direction.DESC,"createdTime")
    //    );
    // 获得评论列表
    //     apCommentList = mongoTemplate.find(query, ApComment.class);

    ApUser user = AppThreadLocalUtils.getUser();
    if (user == null) {
      return ResponseResult.okResult(apCommentList);
    }
    // 封装查询结果
    List<ApCommentVo> apCommentVoList = new ArrayList<>();
    // 获取点赞的id列表
    List<String> idList =
        apCommentList.stream().map(map -> map.getId()).collect(Collectors.toList());
    // 查询点赞的批量列表，按照id!!
    Query query1 =
        Query.query(Criteria.where("CommentId").in(idList).and("authorId").is(user.getId()));
    List<ApCommentLike> apCommentLikes = mongoTemplate.find(query1, ApCommentLike.class);

    if (CollectionUtils.isNotEmpty(apCommentList) && CollectionUtils.isNotEmpty(apCommentLikes)) {
      apCommentList.forEach(
          comment -> {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(comment, apCommentVo);
            apCommentLikes.forEach(
                apCommentLike -> {
                  if (comment.getId().equals(apCommentLike.getCommentId())) {
                    apCommentVo.setOperation((short) 0);
                  }
                });
            apCommentVoList.add(apCommentVo);
          });
      return ResponseResult.okResult(apCommentVoList);
    }

    return ResponseResult.okResult(apCommentList);
  }
}
